package com.license.logic.behaviorlog;

import java.sql.Date;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import com.license.common.util.Constants;
import com.license.common.util.Utils;
import com.license.logic.alimentation.Food;
import com.license.logic.alimentation.FoodCharacteristics;
import com.license.logic.dao.ActivityDao;
import com.license.logic.dao.NutrionDAO;
import com.license.logic.dao.SystemOptionDao;
import com.license.logic.history.GeneticalHistory;
import com.license.logic.history.MedicalHistory;
import com.license.logic.preference.Activity;
import com.license.logic.preference.Nutrition;
import com.license.logic.preference.Preferences;
import com.license.logic.profile.BehavioralProfile;
import com.license.logic.profile.EmployeeProfile;
import com.license.logic.profile.MedicalProfile;
import com.license.logic.profile.PersonalProfile;


public class XmlGeneration {
	
	private List<EmployeeProfile> employeeProfilesList = new ArrayList<EmployeeProfile>();
	private Utils utils = new Utils();
	private Random randomGenerator = new Random();
	private final int NUMBER_GENERATED;
	private final int SEX_MALE = 1;
	private static int employeeCount;
	private final int ACTIVITIES_PER_DAY;
	private final int NINE_HOURS ;
	private final int EIGTH_HOURS;
	private final int BEHAVIOR_LOG_NUMBER_DAY;
	private double MINIM_CALORIE_PER_DAY;
	private double MAXIM_CALORIE_PER_DAY;
	
	private ActivityDao activityDao = new ActivityDao();
	private NutrionDAO nutrionDAO = new NutrionDAO();
	
	private Map <String, Activity> allActivities;
	private Map <String, Food> allFoods;
	
	public XmlGeneration(){
		this.allActivities = activityDao.getAllActivities();
		this.allFoods = new HashMap<String, Food>();
		Map <String, List<Food>> foods = nutrionDAO.getAllFoods();
		for (String key : foods.keySet()){
			for (Food food : foods.get(key)){
				this.allFoods.put(food.getName(), food);
			}
		}
//		this.allFoods = nutrionDAO.getAllFoods();
		SystemOptionDao optionDao = new SystemOptionDao();
		System.out.println(optionDao.getProperty("BEHAVIOR_LOG_NUMBER_DAY"));
		BEHAVIOR_LOG_NUMBER_DAY = Integer.parseInt(optionDao.getProperty("BEHAVIOR_LOG_NUMBER_DAY"));
		EIGTH_HOURS = Integer.parseInt(optionDao.getProperty("EIGTH_HOURS"));
		NINE_HOURS = Integer.parseInt(optionDao.getProperty("NINE_HOURS"));
		ACTIVITIES_PER_DAY = Integer.parseInt(optionDao.getProperty("ACTIVITIES_PER_DAY"));
		NUMBER_GENERATED = Integer.parseInt(optionDao.getProperty("NUMBER_GENERATED"));
	}
	
	public List<EmployeeProfile> generateProfiles(){
		employeeProfilesList.clear();
		for (int i = 0 ; i < NUMBER_GENERATED; i++){
			EmployeeProfile employeeProfile = new EmployeeProfile();
			PersonalProfile personalProfile =generatePersonalProfile();
			employeeProfile.setPersonalProfile(personalProfile);
			MedicalProfile medicalProfile = generateMedicalProfile();
			employeeProfile.setMedicalProfile(medicalProfile);
			employeeProfile.setBehavioralProfiles(generateBehavioralProfile(medicalProfile.getMedicalHistory(), personalProfile));
			employeeProfilesList.add(employeeProfile);
		}
		
		return employeeProfilesList;
	}
	
	private PersonalProfile generatePersonalProfile(){
		employeeCount ++;
		Utils util = new Utils();
		PersonalProfile personalProfile = new PersonalProfile();
		personalProfile.setAge(randomGenerator.nextInt(Constants.AGE_MAXIM_VALUE - Constants.AGE_MINIM_VALUE)+ Constants.AGE_MINIM_VALUE);  
		personalProfile.setSex(randomGenerator.nextInt(1) == SEX_MALE ? "m" : "f");
		personalProfile.setWeight(util.twoDecimalPlaces(randomGenerator.nextInt(Constants.WIEGHT_MAXIM_VALUE- Constants.WEIGHT_MINIM_VALUE) + Constants.WEIGHT_MINIM_VALUE));
		personalProfile.setHeight(util.twoDecimalPlaces(util.generateRandomDouble(Constants.HEIGHT_MINIM_VALUE, Constants.HEIGHT_MAXIM_VALUE)));
		Calendar cal = Calendar.getInstance();
		int dayNumber = randomGenerator.nextInt(100);   // random date from today and 100 day before
		cal.add(Calendar.DAY_OF_YEAR, - dayNumber);
		personalProfile.setStartDate(cal.getTime());
		personalProfile.setName("Employee " + employeeCount);
		Date birthDate = new Date(Constants.CURRENT_YEAR - personalProfile.getAge() - 1900 ,randomGenerator.nextInt(12), randomGenerator.nextInt(30));
		personalProfile.setBirthDate(birthDate);
		
		//generate food preference
		Preferences preference = new Preferences();
		int randomListSize = randomGenerator.nextInt(allFoods.keySet().size()-1);
		List<Food> nutritionList = new ArrayList<Food>();
		Object[] foodValues = allFoods.keySet().toArray();
		for (Integer index : utils.getIntegerList(randomListSize, allFoods.keySet().size())){
			nutritionList.add(allFoods.get(foodValues[index]));
		}
		
		preference.setNutritions(nutritionList);
		
		// generate activity preference
		randomListSize= randomGenerator.nextInt(allActivities.keySet().size()-1);
		List<Activity> activityList = new ArrayList<Activity>();
		Object[] activityValues = allActivities.keySet().toArray();
		
		for (Integer index : utils.getIntegerList(randomListSize, allActivities.keySet().size())){
			activityList.add(allActivities.get(activityValues[index]));
		}
		preference.setActivities(activityList);
		
		personalProfile.setPreference(preference);
		
		if ("f".equals(personalProfile.getSex())){
			this.MAXIM_CALORIE_PER_DAY = Constants.MAXIM_CALORIE_PER_DAY_FOR_FEMALE;
			this.MINIM_CALORIE_PER_DAY = Constants.MINIM_CALORIE_PER_DAY_FOR_FEMALE;
		} else {
			this.MAXIM_CALORIE_PER_DAY = Constants.MAXIM_CALORIE_PER_DAY_FOR_MALE;
			this.MINIM_CALORIE_PER_DAY = Constants.MINIM_CALORIE_PER_DAY_FOR_MALE;
		}
		return personalProfile;
	}
	
	private MedicalProfile generateMedicalProfile(){
		MedicalProfile medicalProfile = new MedicalProfile();
		MedicalHistory medicalHistory = new MedicalHistory();
		GeneticalHistory geneticalHistory = new GeneticalHistory();
		medicalHistory.setSmoker(randomGenerator.nextBoolean());  	
		medicalHistory.setDiabets(randomGenerator.nextBoolean());
		medicalHistory.setSbp(randomGenerator.nextInt(Constants.SBP_MAXIM_VALUE- Constants.SBP_MINIM_VALUE) + Constants.SBP_MINIM_VALUE);                        //values from 80 to 250 
		geneticalHistory.setFamilyCardioHistory(randomGenerator.nextBoolean());
		medicalProfile.setMedicalHistory(medicalHistory);
		medicalProfile.setGeneticalHistory(geneticalHistory);
		return medicalProfile;
	}
	
	private  List<BehavioralProfile> generateBehavioralProfile(MedicalHistory medicalHistory, PersonalProfile personalProfile){
			
		Utils util = new Utils();
		 List<BehavioralProfile> behavioralProfiles = new  ArrayList<BehavioralProfile>();
		 Object[] activitieKeys = allActivities.keySet().toArray();
		 Object[] foodKeys = allFoods.keySet().toArray();
		 
		 double activityKalory = 0.0;
		 double nutritionKalory = 0.0;
		 
		 for ( int r = 0 ; r < BEHAVIOR_LOG_NUMBER_DAY ; r++){
			BehavioralProfile behavioralProfile = new BehavioralProfile();
			behavioralProfile.setDay(r+1);
			int mealsPerDay = util.generateRandomInt(Constants.MINIM_MEALS_PER_DAY, Constants.MAXIM_MEALS_PER_DAY);
			int activitiesPerDay = randomGenerator.nextInt(ACTIVITIES_PER_DAY);
			
			List<Integer> timeAxe = new ArrayList<Integer>();
			List<Activity> activitiesList = new ArrayList<Activity>();
			List<List<Nutrition>> nutritionList = new ArrayList<List<Nutrition>>();
			int indexStart=0, indexEnd=0;
			
			//generate activities
			double activityAuxiliarValue = 0;
			for (int i = 0 ; i < activitiesPerDay; i++){
				Activity activity = new Activity();
				activity.setName(activitieKeys[randomGenerator.nextInt(allActivities.keySet().size()-1)].toString());
				int startTime=randomGenerator.nextInt(EIGTH_HOURS) + NINE_HOURS;;
				int endTime=startTime + randomGenerator.nextInt(60);
				if (!timeAxe.isEmpty()){
					do {
						
						for (int j = 0 ; j < timeAxe.size()-1; j++){
							if ( timeAxe.get(j)< startTime && timeAxe.get(j+i)> startTime){
								indexStart = j;
							}
							if ( timeAxe.get(j)< endTime && timeAxe.get(j+i)> endTime){
								indexEnd = j;
							}
						}
						if (indexEnd- indexStart != 1 || indexStart % 2 == 1){
							
						}
	
						startTime = randomGenerator.nextInt(EIGTH_HOURS) + NINE_HOURS;
						endTime = startTime + randomGenerator.nextInt(60);
					} while (indexEnd- indexStart == 1 && indexStart % 2 == 0);
					timeAxe.add(indexStart, startTime);
					timeAxe.add(indexEnd, endTime);
				}
				Time timeS = new Time(startTime/60, startTime%60, 0);
				Time timeE = new Time(endTime/60, endTime%60, 0);
				
				activity.setEndTime(timeE);
				activity.setStartTime(timeS);
				activitiesList.add(activity);
				activityAuxiliarValue += (endTime-startTime)*allActivities.get(activity.getName()).getKalories()*personalProfile.getWeight() / 60 / 10;
			}
			activityKalory += activityAuxiliarValue;
			behavioralProfile.setActivityList(activitiesList);
			
			//generate nutrition
			double nutritionAuxiliarValue = 0;
			for (int i = 0 ; i < mealsPerDay; i++){
				
				int startTime;
				int endTime;
				if (!timeAxe.isEmpty()){
					do {
	
						startTime = randomGenerator.nextInt(EIGTH_HOURS) + NINE_HOURS;
						endTime = startTime + randomGenerator.nextInt(60);
						
						for (int j = 0 ; j < timeAxe.size()-1; j++){
							if (j==0){
								if (timeAxe.get(0) > startTime){
									indexStart = j;
								}
								if (timeAxe.get(0) > endTime){
									indexEnd = j;
								}
							} else {
								if ( timeAxe.get(j)< startTime && timeAxe.get(j+i)> startTime){
									indexStart = j;
								}
								if ( timeAxe.get(j)< endTime && timeAxe.get(j+i)> endTime){
									indexEnd = j;
								}
							}
							
						}
	
					} while (indexEnd- indexStart == 0 && indexStart % 2 == 0);
					timeAxe.add(indexEnd, endTime);
					timeAxe.add(indexStart, startTime);
				} else {
					startTime=randomGenerator.nextInt(EIGTH_HOURS) + NINE_HOURS;;
					endTime=startTime + randomGenerator.nextInt(60);
				}
				Time timeS = new Time(startTime/60, startTime%60, 0);
				Time timeE = new Time(endTime/60, endTime%60, 0);
				
				List<Nutrition> nutritionPerTime = new ArrayList<Nutrition>();
				do {
					nutritionPerTime.clear();
					nutritionAuxiliarValue = 0;
					int randomFoodEatenSize = utils.generateRandomInt(Constants.MINIM_NUMBER_FOOD_PER_MEAL, Constants.MAXIM_NUMBER_FOOD_PER_MEAL);
					
					for (Integer index : utils.getIntegerList(randomFoodEatenSize, allFoods.keySet().size())){
						FoodCharacteristics nutritionFoodCharacteristic = allFoods.get(foodKeys[index].toString()).getCharacteristics();
						Nutrition  nutrition= new Nutrition();
						nutrition.setName(foodKeys[index].toString());
						nutrition.setPortions(randomGenerator.nextInt(Constants.MAXIM_NUMBER_PORTION_PER_FOOD - 1) + 1);
						nutrition.setEndTime(timeE);
						nutrition.setStartTime(timeS);
						nutritionPerTime.add(nutrition);
						nutritionAuxiliarValue += nutrition.getPortions()* nutritionFoodCharacteristic.getGramsPerPortion() * nutritionFoodCharacteristic.getKalory()/100;
					}
				} while ((nutritionAuxiliarValue - activityAuxiliarValue < this.MINIM_CALORIE_PER_DAY/ mealsPerDay) 
						|| (nutritionAuxiliarValue - activityAuxiliarValue > this.MAXIM_CALORIE_PER_DAY / mealsPerDay));
				nutritionList.add(nutritionPerTime);
				nutritionKalory += nutritionAuxiliarValue;
			}
			
			behavioralProfile.setNutritionList(nutritionList);
			behavioralProfiles.add(behavioralProfile);
		 }
		 
		 medicalHistory.setActivityKalory(util.twoDecimalPlaces(activityKalory/30));
		 medicalHistory.setNutritionKalory(util.twoDecimalPlaces(nutritionKalory/30));
		 
		return behavioralProfiles;
	}
	
	private EmployeeProfile getEmplProfileByRiskFactors( RiskFactor riskFactor){
		EmployeeProfile employeeProfile = new EmployeeProfile();
		
		MedicalProfile medicalProfile = new MedicalProfile();
		MedicalHistory medicalHistory = new MedicalHistory();
		GeneticalHistory geneticalHistory = new GeneticalHistory();
		
		medicalHistory.setDiabets(riskFactor.isDiabetes());
		medicalHistory.setSmoker(riskFactor.isSmoker());
		medicalHistory.setSbp((int)riskFactor.getSbp());
		medicalHistory.setActivityKalory(riskFactor.getAdditional().getAcitivityKalory());
		medicalHistory.setNutritionKalory(riskFactor.getAdditional().getNutriotionKalory());
		
		geneticalHistory.setFamilyCardioHistory(riskFactor.isFamilyCardHistory());
		medicalProfile.setMedicalHistory(medicalHistory);
		medicalProfile.setGeneticalHistory(geneticalHistory);
		
		PersonalProfile personalProfile = new PersonalProfile();
		personalProfile.setSex(riskFactor.getSex());
		personalProfile.setAge(riskFactor.getAdditional().getAge());
		personalProfile.setHeight(riskFactor.getHeight());
		personalProfile.setWeight(riskFactor.getWeight());
		
		employeeProfile.setPersonalProfile(personalProfile);
		employeeProfile.setMedicalProfile(medicalProfile);
		return employeeProfile;
	}
	
	public List<EmployeeProfile> generateProfilesTest(){
		Utils utils = new Utils();
		List<EmployeeProfile> employeeProfiles = new ArrayList<EmployeeProfile>();
		RiskFactor riskFactor = new RiskFactor();
		for (double age : utils.getListFromInterval(Constants.AGE_MINIM_VALUE, Constants.AGE_MAXIM_VALUE)){
			RiskFactorAdditional additional = new RiskFactorAdditional();
			additional.setAge((int)age);
			
			for (double spb : utils.getListFromInterval(Constants.SBP_MINIM_VALUE, Constants.SBP_MAXIM_VALUE)){
				riskFactor.setSbp(spb);
				for (boolean smoker: utils.getBooleanList()){
					riskFactor.setSmoker(smoker);
						for (double height : utils.getListFromInterval(Constants.HEIGHT_MINIM_VALUE, Constants.HEIGHT_MAXIM_VALUE)){
							riskFactor.setHeight(height);
							for (double weight : utils.getListFromInterval(Constants.WEIGHT_MINIM_VALUE, Constants.WIEGHT_MAXIM_VALUE)){
								riskFactor.setWeight(weight);
								for ( boolean familyCardHistory : utils.getBooleanList()){
									riskFactor.setFamilyCardHistory(familyCardHistory);
									for (boolean diabetes : utils.getBooleanList()){
										riskFactor.setDiabetes(diabetes);
										for (String gender : utils.getGenderList()){
											riskFactor.setSex(gender);
											additional.setNutriotionKalory(2000 + randomGenerator.nextInt(1500));
											additional.setAcitivityKalory(150 + randomGenerator.nextInt(850));
											riskFactor.setAdditional(additional);
											employeeProfiles.add(this.getEmplProfileByRiskFactors(riskFactor));
										}
									}
								}
							}
					}
				}
			}
		}
		return employeeProfiles;
	}
}
